package com.crazymaker.springcloud.back.end.config;

import com.crazymaker.springcloud.base.properties.SecurityProperties;
import com.crazymaker.springcloud.base.security.store.CustomRedisTokenStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * token存储配置
 *
 * @author zlt
 */
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
public class TokenStoreConfig
{

    @Autowired
    private RedisConnectionFactory connectionFactory;

    @Autowired
    private SecurityProperties securityProperties;

    @Bean
    @ConditionalOnProperty(prefix = "zlt.oauth2.token.store", name = "type", havingValue = "redis" )
    public TokenStore tokenStore()
    {
        return new CustomRedisTokenStore(connectionFactory, securityProperties);
    }

    @Autowired
    @Bean
    public AuthorizationServerTokenServices authorizationServerTokenServices(
            TokenStore tokenStore,
            ClientDetailsService clientDetailsService,
            UserDetailsService userDetailsService,
            TokenEnhancer tokenEnhancer)
    {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setTokenStore(tokenStore);
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setReuseRefreshToken(true);
        tokenServices.setClientDetailsService(clientDetailsService);
        tokenServices.setTokenEnhancer(tokenEnhancer);
        this.addUserDetailsService(tokenServices, userDetailsService);
        return tokenServices;
    }

    /**
     * auth 生成token 定制化处理
     * 添加一些额外的用户信息到token里面
     *
     * @return TokenEnhancer
     */
    @Bean
    public TokenEnhancer tokenEnhancer()
    {
        return (accessToken, authentication) ->
        {
            final Map<String, Object> additionalInfo = new HashMap<>(1);
            Object principal = authentication.getPrincipal();
            //增加id参数
            if (principal instanceof UserDetails)
            {
                UserDetails user = (UserDetails) principal;
                additionalInfo.put("id", user.getUsername());
            }
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            return accessToken;
        };
    }

    private void addUserDetailsService(DefaultTokenServices tokenServices, UserDetailsService userDetailsService)
    {
        if (userDetailsService != null)
        {
            PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
            provider.setPreAuthenticatedUserDetailsService(new UserDetailsByNameServiceWrapper(userDetailsService));
            tokenServices.setAuthenticationManager(new ProviderManager(Arrays.asList(provider)));
        }

    }

}
